#ifndef _SYS_OP_H
#define _SYS_OP_H
#include <linux/kernel.h>  // sprintf
#include <linux/security.h>
#include <linux/string.h>

#include "list_op.h"

#define LTCS_TRUSTED_DIR  "ltcs"
#define LTCS_TRUSTED_FILE "trusted_elf"

struct dentry* ltcs_dir;
struct dentry* ltcs_trusted_file;

ssize_t ltcs_trusted_read(struct file* file, char __user* ubuf, size_t count,
                          loff_t* ppos)
{
    ssize_t                   ret = 0;
    struct trusted_elf_entry* entry;
    if (*ppos > 0) return ret;

    entry = ltcs_list_del_entry();
    if (!entry) return ret;
    ret = sprintf(ubuf, "%s", entry->file_name);
    ltcs_list_free_entry(entry);

#ifdef DEBUG
    ltcs_list_print_list();
#endif
    *ppos += ret;
    return ret;
}

ssize_t ltcs_trusted_write(struct file* file, const char __user* ubuf,
                           size_t count, loff_t* ppos)
{
    struct trusted_elf_entry* entry;
    char*                     store_buf;
    if (count <= 0) return -EINVAL;

    entry = kzalloc(sizeof(struct trusted_elf_entry), GFP_KERNEL);
    if (!entry) {
        debug_info("alloc memery for trusted_elf_entry failed.\n");
        return count;
    }
    store_buf = kzalloc(count, GFP_KERNEL);
    if (!store_buf) {
        debug_info("alloc memery for store_buf failed.\n");
        kfree(entry);
        return count;
    }

    strncpy(store_buf, ubuf, count);
    entry->file_name = store_buf;
    ltcs_list_add_entry(entry);
#ifdef DEBUG
    ltcs_list_print_list();
#endif
    return count;
}

static const struct file_operations ltcs_fops = {
    // .open = ima_open_policy,
    .write = ltcs_trusted_write,
    .read  = ltcs_trusted_read,
    // .release = ima_release_policy,
    // .llseek = generic_file_llseek,
};

static int ltcs_sysfs_init(void)
{
    ltcs_dir = securityfs_create_dir(LTCS_TRUSTED_DIR, NULL);
    if (IS_ERR(ltcs_dir)) {
        debug_info("%s create failed.\n", LTCS_TRUSTED_DIR);
        return 1;
    }
    ltcs_trusted_file = securityfs_create_file(LTCS_TRUSTED_FILE, 0600,
                                               ltcs_dir, NULL, &ltcs_fops);
    if (IS_ERR(ltcs_trusted_file)) {
        securityfs_remove(ltcs_dir);
        debug_info("create %s failed.\n", LTCS_TRUSTED_FILE);
        return 1;
    }
    debug_info("ltcs fs init\n");
    return 0;
}

static void ltcs_sysfs_free(void)
{
    securityfs_remove(ltcs_trusted_file);
    securityfs_remove(ltcs_dir);
    debug_info("ltcs fs free\n");
    return;
}

#endif /* _SYS_OP_H */
